﻿using System.ComponentModel;
#if (!WINRT)
using System.Windows;
using System.Windows.Interactivity;
#else
using Windows.UI.Xaml;
using System.Windows.Interactivity;
using nRoute.Behaviors.Interactivity;
using Windows.UI.Xaml.Data;
using System;
using System.Reactive.Linq;
using System.Reactive.Concurrency;
using System.Reactive;
using Windows.UI.Xaml.Controls;
#endif

namespace nRoute.Behaviors.Triggers
{
    public class EventTrigger
#if (WINRT)
        : TriggerBase<FrameworkElement>
#else
        : TriggerBase<DependencyObject>
#endif
    {
        public static readonly DependencyProperty EventNameProperty =
            DependencyProperty.Register("EventName", typeof(string), typeof(EventTrigger),
            new PropertyMetadata(Utilities.Compatability.DP_UNSET_VALUE, new PropertyChangedCallback(OnEventNameChanged)));

        private IDisposable _handlerToken;

#region Properties

        [Category("Common Properties")]
        public string EventName
        {
            get { return Convert.ToString(GetValue(EventNameProperty)); }
            set { SetValue(EventNameProperty, value); }
        }

#if (WINRT)

        [Category("Common Properties")]
        [CustomPropertyValueEditor(CustomPropertyValueEditor.PropertyBinding)]
        public Binding EventNameBinding
        {
            get { return GetBinding(EventNameProperty); }
            set { SetBinding<object>(EventNameProperty, value); }
        }

#endif

#endregion

#region Overrides

        protected override void OnAttached()
        {
            base.OnAttached();

            if (_handlerToken == null && !string.IsNullOrWhiteSpace(this.EventName))
            {
                UpdateEventHandler(this.EventName);
            }
        }

        protected override void OnDetaching()
        {
            if (_handlerToken != null)
            {
                _handlerToken.Dispose();
                _handlerToken = null;
            }

            base.OnDetaching();
        }

#endregion

#region Handlers

        private static void OnEventNameChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((EventTrigger)d).UpdateEventHandler(Convert.ToString(e.NewValue));
        }

        private void UpdateEventHandler(string eventName)
        {
            if (_handlerToken != null) 
            {
                _handlerToken.Dispose();
                _handlerToken = null;
            }
            if (this.AssociatedObject == null) return;      // this is to ensure with initial/static set properties the trigger isn't invoked

            if (!string.IsNullOrWhiteSpace(eventName))
            {
                _handlerToken = Observable.FromEventPattern<RoutedEventArgs>(this.AssociatedObject, eventName, Scheduler.CurrentThread)
                    .Subscribe(OnEvent);
            }
        }

        private void OnEvent(EventPattern<RoutedEventArgs> e)
        {
            base.InvokeActions(e.EventArgs);
        }

#endregion

    }
}